package com.ruoyi.web.controller;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.chat.exception.BalanceDeductException;
import com.ruoyi.common.chat.exception.BalanceInsufficientException;
import com.ruoyi.common.chat.exception.ChatConcurrentException;
import com.ruoyi.common.chat.exception.SensitiveWordsException;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.entity.AiModelEntity;
import com.ruoyi.common.entity.ApiKeyEntity;
import com.ruoyi.common.entity.AuthEntity;
import com.ruoyi.common.entity.ResponseEntity;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.WordToTextConverter;
import com.ruoyi.framework.config.properties.FastgptProperties;
import com.ruoyi.framework.config.properties.QwenPlusProperties;
import com.ruoyi.framework.config.properties.QwenVlPlusProperties;
import com.ruoyi.system.chat.chatqwen.entity.ChatRequestEntity;
import com.ruoyi.system.chat.chatqwen.entity.ChatRequestEntity.Message;
import com.ruoyi.system.chat.entity.AiResponseEntity;
import com.ruoyi.system.chat.service.impl.ChatServiceWrapper;
import com.ruoyi.system.domain.BAskLog;
import com.ruoyi.system.domain.BModel;
import com.ruoyi.system.domain.BUser;
import com.ruoyi.system.domain.BUserScore;
import com.ruoyi.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@RestController
@Slf4j
public class ChatController {

    @Autowired
    private ChatServiceWrapper chatService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private FastgptProperties fastgptProperties;

    @Autowired
    private QwenVlPlusProperties qwenVlPlusProperties;

    @Autowired
    private QwenPlusProperties qwenPlusProperties;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @Autowired
    private BAskLogService bAskLogService;

    @Autowired
    private BModelService bModelService;
    @Autowired
    BUserScoreService userScoreService;

    @Autowired
    BUserService userService;

    @PostMapping(value = "/v1/chat/completions/{type}")
    public void chat(@RequestBody ChatRequestEntity chatRequestEntity, @PathVariable("type") String type,
                     HttpServletRequest request,
                     HttpServletResponse response) throws IOException {
        ApiKeyEntity apiKeyEntity = new ApiKeyEntity();
        AiModelEntity aiModelEntity = new AiModelEntity();
        Map aiParams = this.setAiParamsVo();
//        String key = fastgptProperties.getKey();
//        String apiUrl = fastgptProperties.getApiUrl();
        String key = aiParams.get("qwen-plus-key").toString();
        String apiUrl = aiParams.get("api-url").toString();
        String model = aiParams.get("qwen-plus-model").toString();
        String prompt = aiParams.get("text-prompt").toString();
        if(type.equals("0")){//纯文本
            chatRequestEntity.setMessages(this.setTextMessages(chatRequestEntity.getText(),prompt));
        }else if(type.equals("1")){//图片
//            apiUrl = qwenVlPlusProperties.getApiUrl();
//            key = qwenVlPlusProperties.getKey();
//            String model = qwenVlPlusProperties.getModel();
            key = aiParams.get("qwen-vl-plus-key").toString();
            model = aiParams.get("qwen-vl-plus-model").toString();
            prompt = aiParams.get("image-prompt").toString();
            chatRequestEntity.setMessages(this.setImageMessages(chatRequestEntity.getImgUrl(),prompt));
        }else{//文件
            //调用获取文件文本
            String text = WordToTextConverter.extractText(RuoYiConfig.getProfile() + chatRequestEntity.getFileName());
            chatRequestEntity.setMessages(this.setTextMessages(text,prompt));
        }
        chatRequestEntity.setModel(model);
        apiKeyEntity.setKey(key);
        aiModelEntity.setPath(apiUrl);
        chatRequestEntity.setApiKeyEntity(apiKeyEntity);
        chatRequestEntity.setModelEntity(aiModelEntity);

        log.info("chatRequestEntity: {}", chatRequestEntity);
        try {
            chatService.chat(chatRequestEntity, request, response);
        } catch (Exception e) {
            ResponseEntity<AuthEntity> responseEntity = new ResponseEntity<>();
            if (e instanceof BalanceInsufficientException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE_INSUFFICIENT);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof BalanceDeductException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof ChatConcurrentException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_CONCURRENT_ERROR);
                responseEntity.setMessage("网络异常");
            } else if (e instanceof SensitiveWordsException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_SENSITIVE_WORDS_ERROR);
                responseEntity.setMessage("不可输入特殊敏感词");
            } else {
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT);
                log.error("chat failed", e);
            }
            responseEntity.setMessage(e.getMessage());
            String result = objectMapper.writeValueAsString(responseEntity);
            try {
                response.setHeader("Content-Type", "application/json;charset=UTF-8");
                response.getWriter().write(result);
                response.getWriter().flush();
            } catch (Exception e2) {
                log.error("response.getWriter().write/flush() error", e2);
            } finally {
                try { response.getWriter().close(); } catch (Exception e3) {}
            }
        } finally {
            try {
                response.getOutputStream().close();
            } catch (Exception e) {
                // log.error("response.getOutputStream().close() failed: {}", e.getMessage(), e);
            }
        }
    }

    @PostMapping(value = "/v1/chat/completions/patient/{type}")
    public void chatPatient(@RequestBody ChatRequestEntity chatRequestEntity, @PathVariable("type") String type,
                     HttpServletRequest request,
                     HttpServletResponse response) throws IOException {
        ApiKeyEntity apiKeyEntity = new ApiKeyEntity();
        AiModelEntity aiModelEntity = new AiModelEntity();
        Map aiParams = this.setAiParamsVo();
        String key = aiParams.get("qwen-plus-key").toString();
        String apiUrl = aiParams.get("api-url").toString();
        String model = aiParams.get("qwen-plus-model").toString();
        String prompt = aiParams.get("text-prompt").toString();
        if(type.equals("0")){//纯文本
            chatRequestEntity.setMessages(this.setTextMessages(chatRequestEntity.getText(),prompt));
        }else if(type.equals("1")){//图片
            key = aiParams.get("qwen-vl-plus-key").toString();
            model = aiParams.get("qwen-vl-plus-model").toString();
            prompt = aiParams.get("image-prompt").toString();
            chatRequestEntity.setMessages(this.setImageMessages(chatRequestEntity.getImgUrl(),prompt));
        }else{//文件
            //调用获取文件文本
            String text = WordToTextConverter.extractText(RuoYiConfig.getProfile() + chatRequestEntity.getFileName());
            chatRequestEntity.setMessages(this.setTextMessages(text,prompt));
        }
        chatRequestEntity.setModel(model);
        apiKeyEntity.setKey(key);
        aiModelEntity.setPath(apiUrl);
        chatRequestEntity.setApiKeyEntity(apiKeyEntity);
        chatRequestEntity.setModelEntity(aiModelEntity);

        log.info("chatRequestEntity: {}", chatRequestEntity);
        try {
            chatService.chat(chatRequestEntity, request, response);
        } catch (Exception e) {
            ResponseEntity<AuthEntity> responseEntity = new ResponseEntity<>();
            if (e instanceof BalanceInsufficientException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE_INSUFFICIENT);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof BalanceDeductException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof ChatConcurrentException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_CONCURRENT_ERROR);
                responseEntity.setMessage("网络异常");
            } else if (e instanceof SensitiveWordsException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_SENSITIVE_WORDS_ERROR);
                responseEntity.setMessage("不可输入特殊敏感词");
            } else {
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT);
                log.error("chat failed", e);
            }
            responseEntity.setMessage(e.getMessage());
            String result = objectMapper.writeValueAsString(responseEntity);
            try {
                response.setHeader("Content-Type", "application/json;charset=UTF-8");
                response.getWriter().write(result);
                response.getWriter().flush();
            } catch (Exception e2) {
                log.error("response.getWriter().write/flush() error", e2);
            } finally {
                try { response.getWriter().close(); } catch (Exception e3) {}
            }
        } finally {
            try {
                response.getOutputStream().close();
            } catch (Exception e) {
                // log.error("response.getOutputStream().close() failed: {}", e.getMessage(), e);
            }
        }
    }

    @PostMapping(value = "/v1/chat/completions/ask")
    public void chatAsk(@RequestBody ChatRequestEntity chatRequestEntity,
                            HttpServletRequest request,
                            HttpServletResponse response) throws IOException {
        ApiKeyEntity apiKeyEntity = new ApiKeyEntity();
        AiModelEntity aiModelEntity = new AiModelEntity();
        BModel bModel = bModelService.getById(chatRequestEntity.getModelId());
        if(ObjectUtil.isEmpty(bModel)){
            throw new ServiceException("模型不存在");
        }
        String key = bModel.getKValue();
        String apiUrl = fastgptProperties.getApiUrl();
        apiKeyEntity.setKey(key);
        aiModelEntity.setPath(apiUrl);
        chatRequestEntity.setApiKeyEntity(apiKeyEntity);
        chatRequestEntity.setModelEntity(aiModelEntity);
        Map variables = MapUtil.builder().put("book", Arrays.asList(new String[]{bModel.getName()})).build();
        chatRequestEntity.setVariables(variables);
        log.info("chatRequestEntity: {}", chatRequestEntity);
        try {
            AiResponseEntity responseEntity = chatService.chat(chatRequestEntity, request, response);
            String responseString = objectMapper.writeValueAsString(responseEntity);
            JSONObject responseJson = JSONObject.parseObject(responseString);
            boolean success = responseJson.getBoolean("success");
            if(success){
                //保存问答记录
                String content  = responseJson.getString("content");
                int tokenCount = responseJson.getInteger("tokenCount");
                BAskLog bAskLog = new BAskLog();
                bAskLog.setUserId(SecurityUtils.getUserId());
                bAskLog.setModelId(bModel.getId());
                bAskLog.setPKey(bModel.getKValue());
                bAskLog.setQuestion(chatRequestEntity.getMessages().get(chatRequestEntity.getMessages().size()-1).getContent().toString());
                bAskLog.setAnswer(content);
                bAskLog.setTokenCount(tokenCount);
                bAskLog.setCreateTime(new Date());
                bAskLogService.save(bAskLog);

                //用户积分
                BUserScore userScore = new BUserScore();
                userScore.setUserId(SecurityUtils.getUserId());
                userScore.setTaskId(bAskLog.getId());
                userScore.setScore(2);
                userScore.setType(2);
                userScore.setCreateTime(new Date());
                userScore.setCreateBy(SecurityUtils.getUsername());
                userScoreService.save(userScore);

                //更新用户体验状态
                BUser bUser = new BUser();
                bUser.setId(SecurityUtils.getUserId());
                bUser.setIsExperience(1);
                userService.updateById(bUser);
            }
        } catch (Exception e) {
            ResponseEntity<AuthEntity> responseEntity = new ResponseEntity<>();
            if (e instanceof BalanceInsufficientException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE_INSUFFICIENT);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof BalanceDeductException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_BALANCE);
                responseEntity.setMessage("聊天次数已耗尽");
            } else if (e instanceof ChatConcurrentException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_CONCURRENT_ERROR);
                responseEntity.setMessage("网络异常");
            } else if (e instanceof SensitiveWordsException) {
                log.error("chat failed: {}, {}", e.getClass().getSimpleName(), e.getMessage());
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT_SENSITIVE_WORDS_ERROR);
                responseEntity.setMessage("不可输入特殊敏感词");
            } else {
                responseEntity.setCode(ResponseEntity.CODE_ERROR_CHAT);
                log.error("chat failed", e);
            }
            responseEntity.setMessage(e.getMessage());
            String result = objectMapper.writeValueAsString(responseEntity);
            try {
                response.setHeader("Content-Type", "application/json;charset=UTF-8");
                response.getWriter().write(result);
                response.getWriter().flush();
            } catch (Exception e2) {
                log.error("response.getWriter().write/flush() error", e2);
            } finally {
                try { response.getWriter().close(); } catch (Exception e3) {}
            }
        } finally {
            try {
                response.getOutputStream().close();
            } catch (Exception e) {
                // log.error("response.getOutputStream().close() failed: {}", e.getMessage(), e);
            }
        }
    }

    /**
     * 纯文本获取的消息体
     * @param text
     * @return
     */
    public List<Message> setTextMessages(String text,String prompt){
        if(ObjectUtil.isEmpty(prompt)){
            prompt = fastgptProperties.getText();
        }
        List<Message> list = new ArrayList<>();
        Message messageMap = new Message();
        messageMap.setRole("user");
        messageMap.setContent(text);
        Message keyMap = new Message();
        keyMap.setRole("system");
        keyMap.setContent(prompt);
        list.add(messageMap);
        list.add(keyMap);

        return list;
    }

    /**
     * 图片获取的消息体
     * @param url
     * @return
     */
    public List<Message> setImageMessages(String url,String prompt){
        if(ObjectUtil.isEmpty(prompt)){
            prompt = qwenVlPlusProperties.getText();
        }
        List<Message> list = new ArrayList<>();
        Message messageMap = new Message();
        Message keyMap = new Message();
        keyMap.setRole("system");
        keyMap.setContent(prompt);
        messageMap.setRole("user");
        List<Map> contentList = new ArrayList<>();
        Map textMap = MapUtil.builder().put("type", "text").put("text", "按以下字段，解析表格中的内容").build();
        Map imageMap = MapUtil.builder().put("type", "image_url").put("image_url", MapUtil.builder().put("url", url).build()).build();
        contentList.add(textMap);
        contentList.add(imageMap);
        messageMap.setContent(contentList);

        list.add(keyMap);
        list.add(messageMap);

        log.info("imageMessages:{}", JSONObject.toJSONString(list));
        return list;
    }

    public Map setAiParamsVo(){
        Map aiParamsVo = MapUtil.builder()
                .put("qwen-vl-plus-model",qwenVlPlusProperties.getModel())
                .put("qwen-vl-plus-key",qwenVlPlusProperties.getKey())
                .put("image-prompt",qwenVlPlusProperties.getText())
                .put("qwen-plus-model",qwenPlusProperties.getModel())
                .put("qwen-plus-key",qwenPlusProperties.getKey())
                .put("text-prompt",qwenPlusProperties.getText())
                .put("api-url",qwenPlusProperties.getApiUrl())
                .build();
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("ai_prompt");
        List<SysDictData> dictData = sysDictDataService.selectDictDataList(sysDictData);
        if(ObjectUtil.isNotEmpty(dictData)){
            for(SysDictData data : dictData){
                aiParamsVo.put(data.getDictValue(), data.getRemark());
            }
        }

        return aiParamsVo;
    }
}
